from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QFileDialog
import matplotlib.pyplot as plt  # 绘图库
from keras.preprocessing import image
from keras.applications.inception_v3 import preprocess_input
import numpy as np
from keras.models import load_model
import cv2
import os
from PyQt5.QtGui import QIcon
import pickle

# from control_ErWeiMa import Ui_Dialog1


from PyQt5.QtWidgets import QDesktopWidget,QLabel

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap,QPalette
from One_Interface import *
from pyzbar import pyzbar

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow,QMenuBar, QAction, qApp

y = 0
pic_name_num = 1   # todo:这个到底是为什么子窗口返回pic_name_num还是为1，但是第二次返回开始就为0
class MyWindow(QMainWindow, Ui_MainWindow):     # 自己定义一个类，自己是QMainWindow，继承Ui_MainWindow这个界面类
    def __init__(self, parent=None):    #
        super(MyWindow, self).__init__(parent)  #
        self.setupUi(self)                      # 调用自动生成的Ui_MainWindow中的setupUi方法
        self.retranslateUi(self)                # 调用自动生成的Ui_MainWindow中的retranslateUi方法

        self.setWindowIcon(QIcon('logo.png'))
        self.setWindowTitle("Nothing is impossible!")
        self.statusBar().showMessage("提示：放下后停留几秒钟") # 状态栏  加,5000可以只显示五秒

        screen = QDesktopWidget().screenGeometry()  # 显示屏幕的类.获取电脑屏幕大大小
        self.resize(screen.width()-65,screen.height()-70)         # 固定窗口大小,1920*1080不行因为屏幕左边和上面有边框
        self.center()                                  # 居中
        # self.setFixedSize(self.width(), self.height()) # 禁止窗口最大化和禁止窗口拉伸
        # self.use_palette()



        # 以下五句话是定时器1ms执行一次连接ShowCameraOneImage函数的一次截图
        self.capture = cv2.VideoCapture(0)
        self.DoNotShow = False
        self.timer_camera = QTimer()
        self.timer_camera.start(15)  # 1000ms == 1s
        self.timer_camera.timeout.connect(self.ShowCameraFirstImage)  # 连接槽函数ShowCameraOneImage

        self.timer_camera1 = QTimer()
        self.timer_camera1.start(150)  # 1000ms == 1s,所以至少150*10=1.5秒显示一次结果
        self.timer_camera1.timeout.connect(self.predict_one_picture)  # 连接槽函数ShowCameraOneImage


        self.DoNotShow_second = True
        self.timer_camera2 = QTimer()
        self.timer_camera2.start(15)  # 1000ms == 1s,所以至少150*10=1.5秒显示一次结果
        self.timer_camera2.timeout.connect(self.ShowCamera_SecondImage)  # 连接槽函数ShowCameraOneImage



        self.last_result = -1  # 一个判断机制变量
        self.k = 1
        self.sum_price = 0
        self.jj = 0
        self.setWindowIcon(QIcon('logo.png'))



        # 通过StyleSheet设置QWidget背景色
        mainWindowColor = "background-color:#FFE5B2"
        self.setStyleSheet(mainWindowColor)
        # # 加载上次的结果
        # if not os.path.exists('/home/test5_1.txt'):
        #     os.mknod('/home/test5_1.txt')
        # f = open('/home/test5_1.txt', 'rb')
        # if os.path.getsize('/home/test5_1.txt'):
        #     d = pickle.load(f)
        #     self.textEdit.append("%s" % (d))
        # f.close()

        # 通过StyleSheet设置QWidget背景色
        # mainWindowColor = "background-color:#FFE5B2"
        # self.setStyleSheet(mainWindowColor)


    def center(self):
        screen = QDesktopWidget().screenGeometry()  # 显示屏幕的类.获取电脑屏幕大大小
        size = self.geometry()  # 获取应用窗口大小
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)  # 居中

    #  设置背景图片
    def use_palette(self):
        window_pale = QtGui.QPalette()
        window_pale.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap("1.jpg").scaled(self.width(), self.height())))    # 后面.scaled(self.width(), self.height())是为了铺满图片
        self.setPalette(window_pale)



    def showCamera(self):     # 在label_2里面显示摄像头图像
        self.DoNotShow = False
        return

    ############ 一直显示图片
    def ShowCameraFirstImage(self):   # 在label_2里面显示摄像头图像
        from PyQt5.QtGui import QPixmap, QImage
        from PyQt5 import QtGui,QtCore
        import cv2

        if self.DoNotShow:
            return

        # TODO: 没必要从摄像头加载图片
        capture = self.capture               # 这句话是个废话
        run_forever = True
        # 获取一帧
        ret,frame = capture.read()           # ret为true则开摄像头，其实这里已经是截取了一张了，不用打开cv2.imshow再截屏

        # cv2.destroyAllWindows()           # 这句话是为了关闭cv2.imshow（先截取-关闭-打开这个循环,当然这个思想是错误的）
        # cv2.imshow('gmh', frame)

        # 将这一帧转换为灰度图
        # gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        frame = cv2.flip(frame, flipCode=1)  # 水平翻转

        # 获取label_2图像框的大小
        lab_w = self.label_2.width()
        lab_h = self.label_2.height()

        # 裁剪图片和label_2一样大小否则卡
        frame = cv2.resize(frame, (lab_w, lab_h))

        # 将图片转成BGRA模式;
        self.img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA)
        self.QtImg = QtGui.QImage(self.img_rgb.data, self.img_rgb.shape[1], self.img_rgb.shape[0],QtGui.QImage.Format_RGB32)
        # 显示图片到label_2中;
        self.label_2.resize(QtCore.QSize(self.img_rgb.shape[1], self.img_rgb.shape[0]))
        self.label_2.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))



    # todo:我定义在前调用在后为何还是找不到--->最后还是逼我用写入文件的方式才行这个问题以后想想
    def predict_one_picture(self):

        if self.DoNotShow:
            return

        global y,a
        print("y=%d"%(y))
        if(y >= 10):
            y = 0
        if(y == 0):
            a = np.zeros(shape=(10,13),dtype=float)
            print("开始创建了")


        # self.textEdit.setText("")  # 这个就是避免下面写入过textEdit的错误提示再次显示，等下加载就文件里面读取来加载

        global pic_name_num
        global model    # 这个也是很奇怪的问题不加在这里会有local variable 'model' referenced before assignment报错，可能是判断语句和它不在同一列上写才这样
        import cv2

        pwd = os.getcwd()  # 为了获取当前文件的目录下保存的模型

        # if(self.DoNotShow == False and os.path.exists('%s/QT_Predict_fruit.h5' %(pwd))):     # 前提是：按了开启才能保存
        capture = self.capture
        ret, frame = capture.read()
        frame = cv2.flip(frame, flipCode=1)  # 水平翻转
        cv2.imwrite("/home/1.jpg" ,frame * 1)  # *1才为彩色，%d后可接变量

        # 狂阶图片指定尺寸
        target_size = (229, 229)  # fixed size for InceptionV3 architecture  ,,resnet50改为224*224
        print("pic_name_num:%d" % (pic_name_num))
        if (pic_name_num == 1):  # 模型和权重放到这里就不用每次都会加载卡了,只有第一次卡
            # 载入模型
            model = load_model('%s/add_empty_predict_13.h5' %(pwd))  # 保存模型记得加单引号')  # 加载模型记得加单引号,todo:难道说这里加载了返回子窗口再进来就不用加载了为什么？？
            # 加载训练好的模型
            model.load_weights('%s/add_empty_predict_13.h5' %(pwd))  # 加载权重
        image_path = '/home/1.jpg'
        img = image.load_img((image_path), target_size=(229, 229))  # resnet由229*229变224*224



        preds = self.predict(model, img, target_size)  # 记得加self，否则takes 3 positional arguments but 4 were given
        predss = preds.flatten()  # 二维数组转换为一维
        print(type(predss))
        print(predss)

        labels = np.array(
            [u"苹果", u"橙子", u"青苹果", u"桃子", u"柠檬", u"香蕉", u"火龙果", u"橘子", u"梨", u"番石榴", u"八宝粥", u"用手拿着", u"没有"])  # 标签名字 numpy 类型
        prices = np.array(
            ['1','2','3','4','5','6','7','8','9','10','11','12','13'],dtype = np.int64)
        numbers=np.array(
            ['1','1','1','1','1','1','1','1','1','1','1','1','1'],dtype = np.int64)

        a[y,:] = predss # 替换每一行
        print(a)


        if(y == 9):
            self.last = a.mean(axis=0)   # 取列的平均值并且
            print(self.last)
            self.last_max = np.argmax(self.last)  # 取平均值后的一维数组中最大值的索引下标

            print(self.last_max)
            if(self.last[self.last_max]>=0.25):
                if self.last_max != self.last_result: # 一样就不会执行
                    if(self.last_max!=11 and self.last_max!=12):
                        self.sum_price = self.sum_price +prices[self.last_max]
                        self.textEdit.append("%s水果" % (labels[self.last_max]))
                        self.textEdit_2.append("%d件" % (numbers[self.last_max]))
                        self.textEdit_3.append("%d元" % (prices[self.last_max]))
                        self.last_result = self.last_max
                        self.lineEdit.setText("%d件" % (self.k))
                        self.lineEdit_2.setText("%d元" % (self.sum_price))


                        self.k = self.k+1
        y = y + 1


        # print('Predicted:', preds)
        # print(type(preds))

        # todo：这里实现的取最大值和它元素写得太差了

        # for i in range (11):
        #     gg=preds[[i]]
        #     self.textEdit.append("第%s种水果:%s" %(i+1,gg))

        # kk=np.max(preds)
        # ll=np.argmax(preds)
        # print('ll=%d'%(ll))
        # self.textEdit.append("最有可能是第%d种水果，概率为:%s" % (ll+1, kk))  # 这里是因为np.argmax是取第几个元素最大，但它是从1开始数的所以你懂的



        # c = self.textEdit.toPlainText()    # toPlainText来获取toPlainText里面内容,为空也没事？？
        # f = open('/home/test5_1.txt', 'wb')
        # pickle.dump(c, f)
        # f.close()

        # 关闭这个了
        # self.plot_preds(img, preds, labels)

        pic_name_num = 0  # 这句话啊记得放在这里,坑到自己无法自拔每次都是那张图片
        os.remove('/home/1.jpg')   # 删除图片，避免占资源
        # elif not os.path.exists('%s/QT_Predict_fruit.h5' %(pwd)):     # 这里用了elif，，只要if或后续某一个elif之一满足逻辑值为True，则程序执行完对应输出语句后自动结束该轮if-elif（即不会再去冗余地执行后续的elif或else）。 提高效率
        #     self.textEdit.setText("先训练再过来")
        # elif self.DoNotShow == True and os.path.exists('%s/QT_Predict_fruit.h5' %(pwd)):
        #     self.textEdit.setText("先打开摄像头")


    def predict(self,model, img, target_size):   # 也记得加self
        """Run model prediction on image
        Args:
          model: keras model
          img: PIL format image
          target_size: (w,h) tuple
        Returns:
          list of predicted labels and their probabilities
        """
        if img.size != target_size:
            img = img.resize(target_size)

        x = image.img_to_array(img)
        x = np.expand_dims(x, axis=0)
        x = preprocess_input(x)

        preds = model.predict(x)
        print(preds)
        return preds[0]

    # 下面这两句加上plt里面的fontproperties=font就可以在plt绘图中显示中文了

    # def plot_preds(self,image, preds, labels):
    #     """Displays image and the top-n predicted probabilities in a bar graph
    #     在条形图中显示图像和Top-N预测概率
    #     Args:
    #       image: PIL image
    #       preds: list of predicted labels and their probabilities
    #     """
    #     from matplotlib.font_manager import FontProperties
    #     font = FontProperties(fname='/usr/share/fonts/truetype/arphic/ukai.ttc', size=14)  # 不要放外面否则就会说font没定义，除非你里面用global
    #     plt.imshow(image)
    #     plt.axis('off')
    #     plt.figure()
    #     plt.barh([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], preds,
    #              alpha=0.5)  # 10类, Zipai_ResNet50.h5要11因为加了空白 ,,另外alpha是颜色深度没影响,,与labels数量对应就行
    #     plt.yticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], labels, fontproperties=font)  # 刻度,与上面barh开始对应就好
    #     plt.xlabel(u"概率", fontproperties=font)
    #     plt.xlim(0, 1.01)
    #     plt.tight_layout()  # 调整子图之间的间隔来减少堆叠
    #     plt.show()

    def wechat(self):
        if(self.textEdit.toPlainText()==""):
            return
        self.DoNotShow = True
        # self.capture.release()
        # self.hide()

        # self.dia.show()
        # self.dia.capture = cv2.VideoCapture(0)
        # self.dia.DoNotShow = False
        self.DoNotShow_second = False
        self.ShowCamera_SecondImage()


    def ShowCamera_SecondImage(self):

        if self.DoNotShow_second:
            return
        # self.capture = cv2.VideoCapture(0)
        # 读取当前帧

        ret, frame = self.capture.read()
        # 转为灰度图像
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        frame = cv2.resize(frame, (400, 300))
        cv2.imshow('show_the_codes', frame)
        cv2.moveWindow('show_the_codes', (1920 - 400) // 2, (1080 - 300) // 2)  # 要imshow后才能move


        if cv2.waitKey(1) == ord('q'):  # 等待一秒看看按键有无按下按键
            # self.capture.release()  # 都不用release了，用同一个capture
            self.DoNotShow_second = True
            self.DoNotShow = False
            # self.hide()  # 隐藏此窗口
            self.jj = 0
            cv2.destroyAllWindows()   # 关闭摄像头窗口


        barcodes = pyzbar.decode(gray)

        for barcode in barcodes:
            # 提取二维码的边界框的位置
            # 画出图像中条形码的边界框
            (x, y, w, h) = barcode.rect
            cv2.rectangle(gray, (x, y), (x + w, y + h), (0, 0, 255), 2)

            # 提取二维码数据为字节对象，所以如果我们想在输出图像上
            # 画出来，就需要先将它转换成字符串
            barcodeData = barcode.data.decode("utf-8")
            barcodeType = barcode.type

            # 绘出图像上条形码的数据和条形码类型
            text = "{} ({})".format(barcodeData, barcodeType)
            cv2.putText(gray, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
                        .5, (0, 0, 125), 2)

            # 向终端打印条形码数据和条形码类型
            print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))
            # self.label.setText("支付成功")
            self.jj=1


        # cv2.imshow("请扫描二维码", gray)


            # time.sleep(1)
            # self.timer_camera.stop()  # 停下定时器否则会一直执行
        if(self.jj==1):
            self.DoNotShow_second = True
            # self.hide()  # 隐藏此窗口
            self.jj = 0

            self.DoNotShow_second = True
            self.DoNotShow = False
            cv2.destroyAllWindows()  # 关闭摄像头窗口

            self.textEdit.setText("") # 多了这些,让它清空
            self.textEdit_2.setText("")
            self.textEdit_3.setText("")
            self.lineEdit.setText("")
            self.lineEdit_2.setText("")
            self.sum_price = 0
            self.k = 1



    # # # 图像预处理
    # x = image.img_to_array(img)
    # x = np.expand_dims(x, axis=0)
    # x = preprocess_input(x)
    # # 对图像进行分类
    # preds = model.predict(x)
    # # 输出预测概率
    # print ('Predicted:', preds)



    # # 载入模型
    # model = load_model('args.output_model_file')    # 加载模型记得加单引号
    # 本地图片
    # img = Image.open("/home/abc/GuoMinghao/PaiZhao_10*100/test/%d.jpg"%(pic_name_num))
    # preds = predict(model, img, target_size)
    # plot_preds(img, preds,labels)
    # print(666)
    # # 输出预测概率
    # print('Predicted:', preds)
    # print(777)

    # # 图片URL
    # response = requests.get(image_url)
    # img = Image.open(BytesIO(response.content))
    # preds = predict(model, img, target_size)
    # plot_preds(img, preds)
    #


    # #定义登出按钮的功能
    # def logoutEvent(self):
    #     from See_the_visual import MyWindow  # 这个要放到这里面来，否则放外面就报错
    #     self.timer_camera.stop()        # 停下定时器否则会一直执行
    #     self.timer_camera1.stop()
    #     self.capture.release()          # 原来这里在返回主窗口时候是重新加载的此时又是把release去掉的self.capture = cv2.VideoCapture(0)See_the_visual初始化走一遍
    #     self.hide()           #隐藏此窗口
    #     self.log4 = MyWindow()
    #     self.log4.show()       #显示登录窗口
    #                           #必须加上self


        ##　有这窗口才出现
if __name__ == '__main__':        # 本文件才执行，别的不能调用
    app = QApplication(sys.argv)
    myWin = MyWindow()
    myWin.show()
    sys.exit(app.exec_())  # 使用sys.exit()来退出程序比较优雅，调用它能引发SystemExit异常，然后我们可以捕获这个异常做些清理工作。而os._exit()将python解释器直接退出，后面的语句都不会执行。


